#include "driver_cst816.h"
#include "driver_system.h"

#include "jump_table.h"

#include "co_log.h"
#include "app_config.h"
#include "driver_system.h"
#include "sys_utils.h"
#include "os_timer.h"
#include "os_mem.h"
#include "os_msg_q.h"
#include "os_task.h"
#include "string.h"
 

/*********************
 *      INCLUDES
 *********************/
 
/*********************
 *      DEFINES
 *********************/
#define CST816_DEVICE_WRITE_ADDRESS	 	0x2A//0x2A<<1
#define CST816_DEVICE_READ_ADDRESS 		0x2B//0x2B<<1

/**********************
 *  STATIC VARIABLES
 **********************/
 
os_timer_t user_time;

static GPIO_InitTypeDef   GPIO_Handle;
static I2C_HandleTypeDef  CST816_I2C_Handle;

static int cst816s_enter_bootmode(void);
bool ctp_hynitron_update(void);

void cst816_gpio_init(void)
{
	  __SYSTEM_I2C0_MASTER_CLK_SELECT_48M();
    __SYSTEM_GPIO_CLK_ENABLE();
		__SYSTEM_I2C0_CLK_ENABLE();
	
		 #if CST816D_EN
    GPIO_Handle.Pin       = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
    GPIO_Handle.Pull      = GPIO_PULLUP;
    GPIO_Handle.Alternate = GPIO_FUNCTION_1;
    gpio_init(GPIO_D, &GPIO_Handle);
	
    I2C1_Handle.I2Cx = I2C1;
    I2C1_Handle.Init.I2C_Mode = I2C_MODE_MASTER_7BIT;
    I2C1_Handle.Init.SCL_HCNT = 60;
    I2C1_Handle.Init.SCL_LCNT = 65;
    i2c_init(&I2C1_Handle);

		GPIO_Handle.Pin       = GPIO_PIN_4;
		GPIO_Handle.Mode      = GPIO_MODE_EXTI_IT_FALLING;
		GPIO_Handle.Pull      = GPIO_PULLUP;
		gpio_init(GPIO_A, &GPIO_Handle);
		exti_clear_LineStatus(EXTI_LINE4_PA4);
		NVIC_EnableIRQ(GPIO_IRQn);
		// Output 
		GPIO_Handle.Pin       = GPIO_PIN_5;
		GPIO_Handle.Mode      = GPIO_MODE_OUTPUT_PP;
		gpio_init(GPIO_A, &GPIO_Handle);
		#elif CST816T_EN

    GPIO_Handle.Pin       = CST816T_SDA_GPIO_NUM | CST816T_SCL_GPIO_NUM;
    GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
    GPIO_Handle.Pull      = GPIO_PULLUP;
    GPIO_Handle.Alternate = GPIO_FUNCTION_1;
    gpio_init(CST816T_IIC_PORT, &GPIO_Handle);
	
    CST816_I2C_Handle.I2Cx = I2C0;
    CST816_I2C_Handle.Init.I2C_Mode = I2C_MODE_MASTER_7BIT;
    CST816_I2C_Handle.Init.SCL_HCNT = 60;
    CST816_I2C_Handle.Init.SCL_LCNT = 65;
    i2c_init(&CST816_I2C_Handle);

		GPIO_Handle.Pin       = CST816T_EXTI_GPIO_NUM;
		GPIO_Handle.Mode      = GPIO_MODE_EXTI_IT_FALLING;
		GPIO_Handle.Pull      = GPIO_PULLUP;
		gpio_init(CST816T_EXTI_PORT, &GPIO_Handle);
		exti_clear_LineStatus(CST816T_EXTI_LINE);
		exti_interrupt_enable(CST816T_EXTI_LINE);
		NVIC_EnableIRQ(GPIO_IRQn);
		// Output 
		GPIO_Handle.Pin       = CST816T_RST_GPIO_NUM;
		GPIO_Handle.Mode      = GPIO_MODE_OUTPUT_PP;
		gpio_init(CST816T_RST_PORT, &GPIO_Handle);
		
				#endif
}

bool cst816_read_bytes(uint8_t regaddr,uint8_t* pdata,uint16_t len)
{
	  
	return i2c_memory_read(&CST816_I2C_Handle,CST816_DEVICE_READ_ADDRESS,regaddr,pdata, len);
}

/******************************************
	 write bytes
*******************************************/
bool TP_HRS_WriteBytes(uint8_t RegAddr, uint8_t Data)
{
	
	uint8_t data[2];
	data[0]=RegAddr;
	data[1]=Data;
	// twi_master_transfer(TP_HRS_DEVICE_WRITE_ADDRESS, data, 2,true);
	return i2c_memory_write(&CST816_I2C_Handle,CST816_DEVICE_WRITE_ADDRESS,RegAddr,&data[1],1);
//	twi_master_transfer(TP_HRS_DEVICE_WRITE_ADDRESS
}



bool TP_HRS_WriteBytes_updata(uint8_t device_addr,uint16_t RegAddr, uint8_t *Data,uint16_t len,uint8_t lenth)
{
	
	uint8_t data[2];
	#if 1
	data[0]=RegAddr>>8;
	data[1]=RegAddr;
	#else
	data[0]=RegAddr;
	data[1]=RegAddr>>8;
	#endif
	memcpy(&data[2],Data,len);
	return i2c_memory_write(&CST816_I2C_Handle,device_addr,RegAddr,Data,len);

}



bool TP_HRS_read_updata(uint8_t device_addr,uint16_t RegAddr, uint8_t *Data,uint8_t len,uint8_t lenth)
{
	
		uint8_t data[3];
			#if 1
		data[0]=RegAddr>>8;
		data[1]=RegAddr;
			#else
			data[0]=RegAddr;
			data[1]=RegAddr>>8;
			#endif
	return i2c_memory_read(&CST816_I2C_Handle,device_addr+1,RegAddr,Data, len);
//	 twi_master_transfer(device_addr, data, 2,false);
//	 twi_master_transfer(device_addr+1, Data, len,true);
}


static uint8_t tp_temp_id =0;
static uint8_t is_pressed=0;

void user_timetask_funcb(void *arg)
{
	uint8_t TP_type;
	uint16_t pdwSampleX, pdwSampleY;
	uint8_t ucQueryResponse = 0;//ite7259_wait_command_done();
	uint8_t buffer[8];
	//if(is_pressed)
	{
		is_pressed=0;
		cst816_read_bytes(0x00,buffer,7);

		co_printf("\r\n");
		co_printf("%d %d x:%d y:%d \r\n",buffer[0],buffer[2],(((buffer[3]&0x0f)<<8) | buffer[4]),(((buffer[5]&0x0f)<<8) | buffer[6]));
  
	}
		
}
void cst816_init(void)
{
	cst816_gpio_init();
	co_delay_10us(1000);
	CST816_RST_CLR;
	co_delay_10us(1000);
	CST816_RST_SET;
	co_delay_10us(1000);//100ms
	cst816_read_bytes(0xA7,&tp_temp_id,1);
	TP_HRS_WriteBytes(0xFE,0xff);//设置cst816t不进入低功耗睡眠
	//co_printf("TP----- id=%x\n",tp_temp_id);
//	os_timer_init(&user_time,user_timetask_funcb,NULL);
//  os_timer_start(&user_time,40,true);
}



/************************************************************************************
 * @fn      exti_isr
 *
 * @brief   exti interrupt handler
 */
void cst816_exti_isr_handle(void)
{
	#if CST816D_EN
	if (exti_get_LineStatus(EXTI_LINE4_PA4))
	{
		exti_clear_LineStatus(EXTI_LINE4_PA4);
		is_pressed=1;
	}
	#elif CST816T_EN
	if (exti_get_LineStatus(CST816T_EXTI_LINE))
	{
		 printf("CST816T_EXTI_LINE\r\n");
		 exti_clear_LineStatus(CST816T_EXTI_LINE);
		 is_pressed=1;
	}
	#endif

}

#if BOOT_MODE
#define REG_LEN_1B  1
#define REG_LEN_2B  2

#if 1
/*****************************************************************/

static int cst816s_enter_bootmode(void){
	char retryCnt = 50;
	int ret=0;
	co_delay_10us(1000);
	CST816_RST_CLR;
	co_delay_10us(10000);
	CST816_RST_SET;
	co_delay_10us(1000);//10ms
	while(retryCnt--){
		uint8_t cmd[3];
		cmd[0] = 0xAB;
		ret=TP_HRS_WriteBytes_updata(0x6A<<1,0xA001,cmd,1,REG_LEN_2B);
		co_printf("w_ret:%d\r\n",ret);
		co_delay_10us(2000); 
		ret=TP_HRS_read_updata(0x6A<<1,0xA003,cmd,1,REG_LEN_2B);
		co_printf("r_ret:%d\r\n",ret);
		co_printf("cmd:%x\r\n",cmd[0]);
//		if (cmd[0] != 0x55){
		 if (cmd[0] != 0xC1){
			co_delay_10us(200);
			continue;
		}else{
			co_printf("enter_bootmode_ok\r\n");
			return 0;
		}
		co_delay_10us(200);

	}
	return -1;
}
  
 /*
  *
  */	
#define PER_LEN	512
static int cst816s_update(uint16_t startAddr,uint16_t len,const unsigned char *src){
   
#if  0
	uint32_t sum_len;
	uint8_t cmd[10];
	uint8_t  data_send[PER_LEN];

	sum_len = 0;
	uint32_t  k_data=0,b_data=0;
	k_data=len/PER_LEN;
	
	for(uint32_t i=0;i<k_data;i++)
	{
		cmd[0] = startAddr&0xFF;
		cmd[1] = startAddr>>8;
		TP_HRS_WriteBytes_updata(0x6A<<1,0xA014,cmd,2,REG_LEN_2B);
		memcpy(data_send,src,PER_LEN);
		TP_HRS_WriteBytes_updata(0x6A<<1,0xA018,data_send,PER_LEN,REG_LEN_2B);
		co_delay_10us(1000);
		cmd[0] = 0xEE;
		TP_HRS_WriteBytes_updata(0x6A<<1,0xA004,cmd,1,REG_LEN_2B);
		co_delay_10us(5000);

		{
			uint8_t retrycnt = 50;
			while(retrycnt--)
			{
				cmd[0] = 0;
				TP_HRS_read_updata(0x6A<<1,0xA005,cmd,1,REG_LEN_2B);
				if (cmd[0] == 0x55)
				{
					cmd[0] = 0;
					break;
				}
			//	nrf_delay_ms(10);
				co_delay_10us(1000);
			}
		}
		startAddr += PER_LEN;
		src += PER_LEN;
		sum_len += PER_LEN;

	}

	// exit program mode
	cmd[0] = 0x00;
	TP_HRS_WriteBytes_updata(0x6A<<1,0xA003,cmd,1,REG_LEN_2B);
	return 0;
#endif	

#if 1
	uint16_t sum_len, i;
	uint8_t cmd[10]; 
	uint32_t fw_addr_t = 6; //head 6 byte
	#define IIC_FIFO_LEN 32
	if (cst816s_enter_bootmode() == -1)
	{
	 return -1;
	}
	sum_len = 0;

  do{
		if (sum_len >= len)
		{
			return 0;
		}
		
		// send address
		cmd[0] = startAddr&0xFF;
		cmd[1] = startAddr>>8;
		//hctp_write_bytes(0xA014,cmd,2,REG_LEN_2B);
		TP_HRS_WriteBytes_updata(0x6A<<1,0xA014,cmd,2,REG_LEN_2B);
		
		for(i=0;i<(PER_LEN/IIC_FIFO_LEN);i++)//  512/32 
		{
			fw_addr_t = 6 + i*IIC_FIFO_LEN + sum_len;
			TP_HRS_WriteBytes_updata(0x6A<<1,0xA018+i*IIC_FIFO_LEN,(uint8_t*)&app_bin[fw_addr_t],IIC_FIFO_LEN,REG_LEN_2B);
					 
		}

		cmd[0] = 0xEE;
		TP_HRS_WriteBytes_updata(0x6A<<1,0xA004,&cmd[0],1,REG_LEN_2B);
		co_delay_100us(1000);
		{
			uint8_t retrycnt = 50;
			while(retrycnt--)
			{
				cmd[0] = 0;
				TP_HRS_read_updata(0x6A<<1,0xA005,cmd,2,REG_LEN_2B);
				if (cmd[0] == 0x55)
				{
					// success
					break;
				}
				co_delay_100us(100);
			}
		}
		
		startAddr += PER_LEN;
		sum_len += PER_LEN;
	}while(len);
	// exit program mode
	cmd[0] = 0x00;
	TP_HRS_WriteBytes_updata(0x6A<<1,0xA003,&cmd[0],1,REG_LEN_2B);
#endif
}
		 

 /*
  *
  */
static uint32_t cst816s_read_checksum()
{
     union{
         uint32_t sum;
         uint8_t buf[4];
     }checksum;
     uint8_t cmd[3];
     char readback[4] = {0};
 
     if (cst816s_enter_bootmode() == -1){
        return -1;
     }
     
	cmd[0] = 0;
	TP_HRS_WriteBytes_updata(0x6A<<1,0xA003,cmd,1,REG_LEN_2B);
	//nrf_delay_ms(500);
	co_delay_10us(50000);
		 
	checksum.sum = 0;
	TP_HRS_read_updata(0x6A<<1,0xA008,checksum.buf,2,REG_LEN_2B);
	//LOG(LEVEL_INFO,"checksum.sum=%x \r\n",checksum.sum);
	co_printf("checksum.sum=%x \r\n",checksum.sum);
    return checksum.sum;
	
}


/*****************************************************************/
// common

 /*
  *
  */

bool ctp_hynitron_update(void)
 {
	uint8_t lvalue;
	uint8_t write_data[2];
	bool temp_result = true;
	if (cst816s_enter_bootmode() == 0){
		if(sizeof(app_bin) > 10){
		    uint16_t startAddr = app_bin[1];
		    uint16_t length = app_bin[3];					
		    uint16_t checksum = app_bin[5];
		    startAddr <<= 8; startAddr |= app_bin[0];
		    length <<= 8; length |= app_bin[2];
		    checksum <<= 8; checksum |= app_bin[4];  
				co_printf("app_sum:%x\r\n",checksum);
//		    if(cst816s_read_checksum(startAddr, length)!= checksum){
					if(cst816s_read_checksum()!= checksum){
						co_printf("start !\r\n");
		        cst816s_update(startAddr, length, &app_bin[6]);
		        cst816s_read_checksum();		
						
		    }
		}
		
		return true;
	}
	return false;
 }


#endif
 
//void ite7259_enter_sleep_mode(void)
//{
//	uint8_t pucCommandBuffer[16];
//	uint8_t ucQuery = ite7259_wait_command_done();
//	ASSERT(0x00 == (ucQuery & QUERY_BUSY));
//	LOG_INFO(LEVEL_INFO,"ite7259_enter_sleep_mode \r\n");

//	pucCommandBuffer[0] = 0x04;
//	pucCommandBuffer[1] = 0x00;
//	pucCommandBuffer[2] = 0x01;
//	bool ret = WriteCommandBuffer(pucCommandBuffer, 3);
//	ASSERT(0 == ret);
//}
#endif
